package com.qf.factory;

import com.qf.dao.UserDao;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Properties;

public class BeanFactory {

    public static Object getBean(String id) throws Exception {
        Properties properties = new Properties();
        properties.load(BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"));

        String className = properties.getProperty(id);

        Class<?> cls = Class.forName(className);

        Object obj = cls.newInstance();

        /*这里是所有对象统一管理的位置，我们需要在这里做对象功能的改变 -- 动态代理(jdk的技术)
        返回的不再是原来这个对象，应该返回一个改变功能之后的对象。首先应该创建一个功能改变之后的对象 -- 动态代理(jdk的技术)

        传统方式创建对象的过程：Xxx.java--javac-->Xxx.class--类加载器-->Class<Xxx>--new-->Xxx对象
        如果按照传统方式创建一个功能改变之后的对象，必须先有一个功能改变之后的java类文件
        但是现在我们没有这个类文件，而我们还是想创建对象，我们必须依赖于JVM动态帮我们创建一个Class对象（类加载器+类型）
         */

        /*
            ClassLoader loader：类加载器，目的是在jvm内存中动态创建Class对象的
            Class[] interfaces: 告诉jvm虚拟机动态创建的这个Class对象是什么类型（java中一个类是可以同时实现多个接口的，所以这里是一个接口类型数组）
            InvocationHandler h: 用来给我们封装增强逻辑的，当我们调用代理对象方法时，最终会执行到这个handler的invoke方法

            优点：我们不需要写任何的类文件了，同时我们不需要对原本对象功能的具体实现做任何了解
                    我们只需要知道我们要干嘛
         */
        Object proxy = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
            /*
                Object proxy:就是当前的代理对象(这个对象一定要慎重使用，一般不用)
                Method method：当前代理对象调用的那个方法的反射对象形式
                Object[] args:当前代理对象调用的那个方法的参数值
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                //对find相关方法实现增强操作
                if (method.getName().startsWith("find")){
                    System.out.println("查找缓存~~");
                }

                //当调用代理对象方法时，需要执行原本对象（obj）的功能
                //如果我调用的是代理对象的findAll方法，那么这里就需要调用原本对象的findAll方法
                //如果我调用的是代理对象的findById方法，那么这里就需要调用原本对象的findById方法
                return method.invoke(obj,args);
            }
        });
//        return obj;

        return proxy;
    }

}
